home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The X-Philes (2nd Revision)
/
The X-Philes Number 1 (1995).iso
/
xphiles
/
hp48_2
/
vsrc.tar
/
voyager7_src
/
tree.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-02-27
|
7KB
|
413 lines
/*
// Abstract:
// TREE---Balanced Binary Tree Routines
//
// The Balanced Binary Tree Routines module contains routines for
// handling Balanced Binary Trees.
//
// See The Art of Computer Programming / Volume 3 / Searching and
// Sorting, Donald E. Knuth, pp 451-457.
//
// Author:
// Derek S. Nickel
//
// Creation date:
// 11 November 1990
//
// History:
// V01-001 Derek S. Nickel 11-NOV-1990
// Original.
//
*/
#include <stddef.h>
#include <stdio.h>
#pragma check_stack+
typedef unsigned long cond_value;
typedef unsigned long mask_longword;
const cond_value lib$_normal = 0x00000001;
const cond_value lib$_keyalrins = 0x00158021;
const cond_value lib$_keynotfou = 0x001582FC;
typedef struct _inode_t inode_t;
struct _inode_t {
inode_t *llink;
inode_t *rlink;
short b;
};
#define LLINK(P) (P)->llink
#define RLINK(P) (P)->rlink
#define B(P) (P)->b
//#define TRACE(txt) printf("Trace: %s\n",txt)
#define TRACE(txt)
/***********************************************************************
insert_tree
***********************************************************************/
cond_value insert_tree(
inode_t **treehead,
void *K,
mask_longword *flags,
int (*compare_rtn)(),
int (*allocate_rtn)(),
void **new_node,
void *user_data )
{
inode_t *P;
inode_t *Q;
inode_t *R;
inode_t *S;
inode_t *T;
int a;
int cmp;
/*
// A0. [New tree?]
*/
if (*treehead == NULL) {
TRACE("new binary tree");
(*allocate_rtn)(K,treehead,user_data);
LLINK(*treehead) = RLINK(*treehead) = NULL;
B(*treehead) = 0;
*new_node = *treehead;
return lib$_normal;
}
/*
// A1. [Initialize.] (The pointer variable P will move down the
// tree; S will point to the place where rebalancing may be
// necessary, and T always points to the father of S.
*/
T = (inode_t *)treehead;
S = P = *treehead;
/*
// A2. [Compare.]
*/
A2:
cmp = (*compare_rtn)(K,&P);
if (cmp < 0) {
/*
// A3. [Move left.]
*/
Q = LLINK(P);
if (Q == NULL) {
(*allocate_rtn)(K,&Q,user_data);
LLINK(P) = Q;
goto A5;
} else {
if (B(Q) != 0) {
T = P;
S = Q;
}
P = Q;
goto A2;
}
} else if (cmp > 0) {
/*
// A4. [Move right.]
*/
Q = RLINK(P);
if (Q == NULL) {
cmp = (*allocate_rtn)(K,&Q,user_data);
RLINK(P) = Q;
goto A5;
} else {
if (B(Q) != 0) {
T = P;
S = Q;
}
P = Q;
goto A2;
}
} else {
*new_node = P;
return lib$_keyalrins;
}
/*
// A5. [Insert.] (We have just linked a new node, NODE(Q), into
// the tree and its fields need to be initialized.
*/
A5:
/* KEY(Q) = K; - done by allocate routine */
LLINK(Q) = RLINK(Q) = NULL;
B(Q) = 0;
*new_node = Q;
/*
// A6. [Adjust balance factors.] (Now that the balance factors
// on the nodes between A and Q need to be changed from zero to
// +/- one.)
*/
cmp = (*compare_rtn)(K,&S);
if (cmp < 0)
R = P = LLINK(S);
else
R = P = RLINK(S);
while (P != Q) {
cmp = (*compare_rtn)(K,&P);
if (cmp < 0) {
B(P) = -1;
P = LLINK(P);
} else if (cmp > 0) {
B(P) = +1;
P = RLINK(P);
}
}
/*
// A7. [Balancing act.]
*/
cmp = (*compare_rtn)(K,&S);
if (cmp < 0) a = -1;
else a = 1;
if (B(S) == 0) {
/*
// i) the tree has grown higher.
*/
B(S) = a;
return lib$_normal;
} else if (B(S) == -a) {
/*
// ii) the tree has gotten more balanced.
*/
B(S) = 0;
return lib$_normal;
} else if (B(S) == a) {
/*
// iii) the tree has gotton out of balance.
*/
if (B(R) == a)
goto A8;
else if (B(R) == -a)
goto A9;
}
/*
// A8. [Single rotation.]
*/
A8:
TRACE("Single rotation");
P = R;
if (a == 1) {
RLINK(S) = LLINK(R);
LLINK(R) = S;
} else {
LLINK(S) = RLINK(R);
RLINK(R) = S;
}
B(S) = B(R) = 0;
goto A10;
/*
// A9. [Double rotation.]
*/
A9:
TRACE("Double rotation");
if (a == 1) {
P = LLINK(R);
LLINK(R) = RLINK(P);
RLINK(P) = R;
RLINK(S) = LLINK(P);
LLINK(P) = S;
} else {
P = RLINK(R);
RLINK(R) = LLINK(P);
LLINK(P) = R;
LLINK(S) = RLINK(P);
RLINK(P) = S;
}
if (B(P) == a) {
B(S) = -a;
B(R) = 0;
} else if (B(P) == 0) {
B(S) = 0;
B(R) = 0;
} else if (B(P) == -a) {
B(S) = 0;
B(R) = a;
}
B(P) = 0;
goto A10;
/*
// A10. [Finishing touch.] We have completed the rebalancing
// trasformation, taking (1) to (2) (see KNUTH), with P pointing
// to the new root and T pointing to the father of the old root.
*/
A10:
if (S == RLINK(T))
RLINK(T) = P;
else
LLINK(T) = P;
return lib$_normal;
}
/***********************************************************************
lookup_tree
***********************************************************************/
cond_value lookup_tree(
inode_t **treehead,
void *K,
int (*compare_rtn)(),
inode_t **new_node )
{
inode_t *node;
int cmp;
node = *treehead;
while (node != NULL) {
cmp = (*compare_rtn)(K,&node);
if (cmp < 0)
node = node->llink;
else if (cmp > 0)
node = node->rlink;
else {
*new_node = node;
return lib$_normal;
}
}
*new_node = NULL;
return lib$_keynotfou;
}
/***********************************************************************
preorder_traversal
***********************************************************************/
static cond_value preorder_traversal(
inode_t **treehead,
int (*action_rtn)(),
void *user_data )
{
inode_t *node;
node = *treehead;
(*action_rtn)(node,user_data);
if (node->llink != NULL)
preorder_traversal(&node->llink,action_rtn,user_data);
if (node->rlink != NULL)
preorder_traversal(&node->rlink,action_rtn,user_data);
return lib$_normal;
}
/***********************************************************************
inorder_traversal
***********************************************************************/
static cond_value inorder_traversal(
inode_t **treehead,
int (*action_rtn)(),
void *user_data )
{
inode_t *node;
node = *treehead;
if (node->llink != NULL)
inorder_traversal(&node->llink,action_rtn,user_data);
(*action_rtn)(node,user_data);
if (node->rlink != NULL)
inorder_traversal(&node->rlink,action_rtn,user_data);
return lib$_normal;
}
/***********************************************************************
postorder_traversal
***********************************************************************/
static cond_value postorder_traversal(
inode_t **treehead,
int (*action_rtn)(),
void *user_data )
{
inode_t *node;
node = *treehead;
if (node->llink != NULL)
postorder_traversal(&node->llink,action_rtn,user_data);
if (node->rlink != NULL)
postorder_traversal(&node->rlink,action_rtn,user_data);
(*action_rtn)(node,user_data);
return lib$_normal;
}
/***********************************************************************
traverse_tree
***********************************************************************/
cond_value traverse_tree(
inode_t **treehead,
int (*action_rtn)(),
void *user_data )
{
if (*treehead == NULL) {
return lib$_normal;
} else {
return inorder_traversal(treehead,action_rtn,user_data);
}
}
/***********************************************************************
post_order_traversal
***********************************************************************/
cond_value post_order_traversal(
inode_t **treehead,
int (*action_rtn)(),
void *user_data )
{
if (*treehead == NULL) {
return lib$_normal;
} else {
return postorder_traversal(treehead,action_rtn,user_data);
}
}